package com.itxiao.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itxiao.constants.Constants;
import com.itxiao.dao.*;
import com.itxiao.entity.*;
import com.itxiao.pojo.bo.Page;
import com.itxiao.pojo.bo.spu.UpdateShipBo;
import com.itxiao.pojo.dto.AddCartDto;
import com.itxiao.pojo.dto.CalculateOrderShippingDto;
import com.itxiao.pojo.vo.R;
import com.itxiao.service.ShippingTemplateService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * (ShippingTemplate)表服务实现类
 *
 * @author makejava
 * @since 2025-10-12 17:07:25
 */
@Service
public class ShippingTemplateServiceImpl extends ServiceImpl<ShippingTemplateDao, ShippingTemplate> implements ShippingTemplateService {

    @Resource
    private ShippingTemplateDao shippingTemplateDao;
    @Resource
    private ShippingRuleDao shippingRuleDao;
    @Resource
    private SpuDao  spuDao;
    @Resource
    private SkuDao  skuDao;
    @Resource
    private UserAddressDao userAddressDao;

    @Override
    public R queryList(Page page) {
        // 1. 查询所有运费模板
        List<ShippingTemplate> shippingTemplates = shippingTemplateDao.selectList(null);

        if (shippingTemplates.isEmpty()) {
            return R.ok(Collections.emptyList());
        }

        // 2. 提取模板 ID 列表
        List<Long> templateIds = shippingTemplates.stream()
                .map(ShippingTemplate::getId)
                .collect(Collectors.toList());

        // 3. 查询所有相关运费规则，并按 templateId 分组
        List<ShippingRule> allRules = shippingRuleDao.selectList(
                new QueryWrapper<ShippingRule>().in("template_id", templateIds).orderByAsc("id")
        );
        // 按 template_id 分组，便于快速查找
        Map<Long, List<ShippingRule>> rulesMap = allRules.stream()
                .collect(Collectors.groupingBy(ShippingRule::getTemplateId));

        // 4. 组装成 UpdateShipBo 列表
        List<UpdateShipBo> result = shippingTemplates.stream().map(template -> {
            UpdateShipBo bo = new UpdateShipBo();
            bo.setId(template.getId());
            bo.setName(template.getName());
            bo.setPricingMethod(template.getPricingMethod()); // 假设字段名一致
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            bo.setCreateTime(sdf.format(template.getCreateTime()));
            // 获取该模板对应的规则列表，若无则为空列表
            bo.setRules(rulesMap.getOrDefault(template.getId(), Collections.emptyList()));

            return bo;
        }).collect(Collectors.toList());
        Map<String, Object> data = new HashMap<>();
        data.put("list", result);

        // 5. 返回结果
        return R.ok(data);
    }

    @Override
    @Transactional
    public R add(UpdateShipBo bo) {
        ShippingTemplate shippingTemplate = new ShippingTemplate();
        shippingTemplate.setName(bo.getName());
        shippingTemplate.setPricingMethod(bo.getPricingMethod());

        int insert = shippingTemplateDao.insert(shippingTemplate);
        if (insert == 0 ){
            return R.fail("插入失败");
        }
        for (ShippingRule rule : bo.getRules()) {
            ShippingRule shippingRule = new ShippingRule();
            shippingRule.setTemplateId(shippingTemplate.getId());
            BeanUtils.copyProperties(rule, shippingRule);
            int insert1 = shippingRuleDao.insert(shippingRule);
            if (insert1 == 0){
                R.fail("插入规则失败");
            }
        }
        return null;
    }

    @Override
    public R edit(UpdateShipBo bo) {

        return null;
    }

    @Override
    public R del(List<Integer> ids) {
        return null;
    }

    @Override
    public R calculateOrderShipping(CalculateOrderShippingDto bo) {
        // 计算订单运费逻辑，按照件数和按照重量
        if (bo.getAddressId() == null || bo.getSpuList() == null || bo.getSpuList().isEmpty()) {
            return R.fail("参数缺失");
        }

        // Step 2: 查询收货地址
        // 注意：addressId 是 Integer，但数据库 ID 通常是 Long，需转换
        UserAddress address = userAddressDao.selectById(bo.getAddressId().longValue());
        if (address == null) {
            return R.fail("收货地址不存在");
        }
        String[] userRegions = address.getRegionCode().split(","); // 省,市,区

        // Step 3: 查询所有商品（SPU + SKU）
        // 修复：使用 AddCartDto，不是 SpuItem
        List<Long> spuIds = bo.getSpuList().stream()
                .map(AddCartDto::getSpuId)  // ✅ 正确引用
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        List<Spu> spuList = spuDao.selectBatchIds(spuIds);
        if (spuList.size() != new HashSet<>(spuIds).size()) {
            return R.fail("存在无效商品");
        }
        Map<Long, Spu> spuMap = spuList.stream().collect(Collectors.toMap(Spu::getId, Function.identity()));

        List<Long> skuIds = bo.getSpuList().stream()
                .map(AddCartDto::getSkuId)
                .filter(Objects::nonNull)
                .filter(id -> id > 0)
                .collect(Collectors.toList());
        Map<Long, Sku> skuMap = Collections.emptyMap();
        if (!skuIds.isEmpty()) {
            List<Sku> skuList = skuDao.selectBatchIds(skuIds);
            skuMap = skuList.stream().collect(Collectors.toMap(Sku::getId, Function.identity()));
        }

        // Step 4: 按商品分组统计数量
        Map<Long, Integer> spuQuantityMap = new HashMap<>();
        Map<Long, Integer> skuQuantityMap = new HashMap<>();
        // 修复：使用 AddCartDto
        for (AddCartDto item : bo.getSpuList()) {
            spuQuantityMap.merge(item.getSpuId(), item.getQuantity(), Integer::sum); // int 可自动转 Integer
            if (item.getSkuId() != null && item.getSkuId() > 0) {
                skuQuantityMap.merge(item.getSkuId(), item.getQuantity(), Integer::sum);
            }
        }

        // Step 5: 提取使用了运费模板的商品
        Set<Long> templateIds = new HashSet<>();
        Map<Long, Spu> spuWithTemplate = new HashMap<>();
        Map<Long, Spu> spuWithoutTemplate = new HashMap<>();

        for (Spu spu : spuMap.values()) {
            if (spu.getExpressTemplateId() != null && spu.getExpressTemplateId() > 0) {
                spuWithTemplate.put(spu.getId(), spu);
                templateIds.add(spu.getExpressTemplateId());
            } else {
                spuWithoutTemplate.put(spu.getId(), spu);
            }
        }

        double totalFee = 0.0;

        // Step 6: 处理无模板商品（直接加 expressFee * 数量）
        for (Spu spu : spuWithoutTemplate.values()) {
            Integer qty = spuQuantityMap.get(spu.getId());
            if (qty != null) {
                totalFee += spu.getExpressFee() * qty;
            }
        }

        // 如果没有使用模板的商品，直接返回
        if (templateIds.isEmpty()) {
            return R.ok(Collections.singletonMap("totalFee", round2(totalFee)));
        }

        // Step 7: 查询模板和规则
        List<ShippingTemplate> templates = shippingTemplateDao.selectBatchIds(templateIds);
        Map<Long, String> templateMethodMap = templates.stream()
                .collect(Collectors.toMap(ShippingTemplate::getId, ShippingTemplate::getPricingMethod));

        List<ShippingRule> rules = shippingRuleDao.selectList(
                new LambdaQueryWrapper<ShippingRule>().in(ShippingRule::getTemplateId, templateIds)
        );
        if (rules.isEmpty()) {
            return R.fail("未配置运费规则");
        }

        // Step 8: 匹配地区，筛选出当前地址适用的规则
        Map<Long, ShippingRule> validRuleMap = new HashMap<>();
        Set<Long> supportedTemplates = new HashSet<>();

        for (ShippingRule rule : rules) {
            if (isAreaMatch(rule.getArea(), userRegions)) {
                validRuleMap.put(rule.getTemplateId(), rule);
                supportedTemplates.add(rule.getTemplateId());
            }
        }

        // 校验：所有模板都必须支持该地区
        if (!supportedTemplates.containsAll(templateIds)) {
            return R.fail("部分商品不支持配送到该地区");
        }

        // Step 9: 分别处理按件和按重
        for (Spu spu : spuWithTemplate.values()) {
            Long templateId = spu.getExpressTemplateId();
            ShippingRule rule = validRuleMap.get(templateId);
            if (rule == null) continue;

            String method = templateMethodMap.get(templateId);
            Integer quantity = spuQuantityMap.get(spu.getId());
            if (quantity == null || quantity <= 0) continue;

            if (Constants.QUANTITY_BILLING.equals(method)) {
                // 按件计费
                if (quantity == 1) {
                    totalFee += rule.getFirstPiecePrice();
                } else {
                    totalFee += rule.getFirstPiecePrice() + rule.getAddPiecePrice() * (quantity - 1);
                }
            } else if (Constants.WEIGHT_BILLING.equals(method)) {
                // 按重计费
                double totalWeight = 0.0;
                for (AddCartDto item : bo.getSpuList()) { // 修复：用 AddCartDto
                    if (item.getSpuId().equals(spu.getId()) && item.getSkuId() != null) {
                        Sku sku = skuMap.get(item.getSkuId());
                        if (sku != null && sku.getWeight() != null) {
                            totalWeight += sku.getWeight() * item.getQuantity(); // int 可参与计算
                        }
                    }
                }

                if (totalWeight <= rule.getFirstWeight()) {
                    totalFee += rule.getFirstWeightPrice();
                } else {
                    double overWeight = totalWeight - rule.getFirstWeight();
                    double unit = rule.getAddWeightUnit() > 0 ? rule.getAddWeightUnit() : 1.0;
                    long units = (long) Math.ceil(overWeight / unit);
                    totalFee += rule.getFirstWeightPrice() + rule.getAddWeightPrice() * units;
                }
            }
        }

        // Step 10: 返回结果（保留两位小数）✅ 修复语法错误
        return R.ok(Collections.singletonMap("totalFee", round2(totalFee)));
    }

    // 判断地区是否匹配（简单版：area 是逗号分隔的区域码）
    private boolean isAreaMatch(String area, String[] userRegions) {
        if (area == null || userRegions == null) return false;
        Set<String> areaSet = Arrays.stream(area.split(","))
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .collect(Collectors.toSet());
        return Arrays.stream(userRegions).anyMatch(areaSet::contains);
    }

    // 保留两位小数
    private Double round2(double v) {
        return Math.round(v * 100.0) / 100.0;
    }
}

